﻿using CemsTransfer.BUS;
using CemsTransfer.Models;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System;
using System.Diagnostics.Metrics;
using System.Dynamic;
using System.IO.Ports;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Security.Cryptography.Xml;
using System.Text;
using System.Timers;
using Timer = System.Timers.Timer;

namespace CemsTransfer.Event
{
    public class CemsDataProcess
    {
        public static List<DeviceInfo> deviceInfos = new List<DeviceInfo>();
        public static List<CmdInfo> cmdInfos = new List<CmdInfo>();
        public int interval = 0;
        public Socket server;//平台TCP
        public Thread thread;
        public bool server_flag = false;
        public string server_ip;
        public int server_port;
        public static object sendlocker = new object();
        public static int NetWorkNum;
        public static bool serial_state = false;
        #region 串口
        public static SerialPort myS0SerialPort_1 = new SerialPort();
        public void OpenSerialPort(string portName, int baudRate, int parity, int dataBits, int stopBits)
        {
            try
            {
                SetS0SerialPortConfig(portName, baudRate, parity, dataBits, stopBits);
                myS0SerialPort_1.Open();
                serial_state = true;
            }
            catch (Exception e)
            {
            }
        }

        private Timer SerialPortRecvTimerS0_1;
        private static int byteLength = 40960;
        public byte[] byteSerialPortRecvS0_1 = new byte[byteLength];
        public event EventHandler<SerialPort485_1RecvEventArgs> ReceivedDataEventS0_1;
        private static int pSerialPortRecv_S0_1 = 0;

        public class SerialPort485_1RecvEventArgs : EventArgs
        {
            /// <summary>
            /// 广播 收到的串口数据
            /// </summary>
            public readonly byte[] RecvData_485_1 = new byte[byteLength];

            /// <summary>
            /// 收到数据 的 长度
            /// </summary>
            public readonly int RecvDataLength_485_1;

            /// <summary>
            /// 将 收到的数据 转化成 待广播的数据
            /// </summary>
            public SerialPort485_1RecvEventArgs(byte[] recvData, int recvDataLength)
            {
                recvData.CopyTo(RecvData_485_1, 0);
                RecvDataLength_485_1 = recvDataLength;
            }
        }

        private void SetS0SerialPortConfig(string portName, int baudRate, int parity, int dataBits, int stopBits)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                portName = $"/dev/{portName}";
            }
            // 串口 参数设置
            myS0SerialPort_1.PortName = portName;
            myS0SerialPort_1.BaudRate = baudRate;
            switch (parity)
            {
                case 0:
                default:
                    myS0SerialPort_1.Parity = Parity.None;
                    break;
                case 1:
                    myS0SerialPort_1.Parity = Parity.Odd;
                    break;
                case 2:
                    myS0SerialPort_1.Parity = Parity.Even;
                    break;
                case 3:
                    myS0SerialPort_1.Parity = Parity.Mark;
                    break;
                case 4:
                    myS0SerialPort_1.Parity = Parity.Space;
                    break;
            }
            myS0SerialPort_1.DataBits = ((4 < dataBits) && (dataBits < 9)) ? dataBits : 8;
            switch (stopBits)
            {
                case 0:
                    myS0SerialPort_1.StopBits = StopBits.None;
                    break;
                case 1:
                default:
                    myS0SerialPort_1.StopBits = StopBits.One;
                    break;
                case 2:
                    myS0SerialPort_1.StopBits = StopBits.OnePointFive;
                    break;
                case 3:
                    myS0SerialPort_1.StopBits = StopBits.Two;
                    break;
            }
            //my485SerialPort_1.ReadTimeout = 200;
            myS0SerialPort_1.RtsEnable = true;
            myS0SerialPort_1.DataReceived += new SerialDataReceivedEventHandler(DataReceived_ttyS0);

            // 串口 接收数据处理定时器 参数设置
            SerialPortRecvTimerS0_1 = new System.Timers.Timer();
            SerialPortRecvTimerS0_1.Interval = 100;
            SerialPortRecvTimerS0_1.AutoReset = false;
            SerialPortRecvTimerS0_1.Elapsed += new ElapsedEventHandler(SPRecvTimer_Tick_ttyS0_1);
        }

        private void SPRecvTimer_Tick_ttyS0_1(object sender, EventArgs e)
        {
            byte[] TemporaryData = new byte[byteLength];
            int TemporaryDataLength = 0;

            if (ReceivedDataEventS0_1 != null)
            {
                byteSerialPortRecvS0_1.CopyTo(TemporaryData, 0);
                TemporaryDataLength = pSerialPortRecv_S0_1;

                ReceivedDataEventS0_1.Invoke(this, new SerialPort485_1RecvEventArgs(TemporaryData, TemporaryDataLength));
                // 数据处理完后，将指针指向数据头，等待接收新的数据
                pSerialPortRecv_S0_1 = 0;
            }
        }

        private void DataReceived_ttyS0(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPortRecvTimerS0_1.Stop();

            try
            {
                byte[] ReadBuf = new byte[myS0SerialPort_1.BytesToRead];
                if (pSerialPortRecv_S0_1 > byteLength - ReadBuf.Length)
                {
                    pSerialPortRecv_S0_1 = 0;
                }
                myS0SerialPort_1.Read(ReadBuf, 0, ReadBuf.Length);
                ReadBuf.CopyTo(byteSerialPortRecvS0_1, pSerialPortRecv_S0_1);
                pSerialPortRecv_S0_1 += ReadBuf.Length;

                try
                {
                    SendToServerMsg(ReadBuf);
                }
                catch (Exception ex)
                {
                }
            }
            catch (Exception ex)
            {
            }
            SerialPortRecvTimerS0_1.Start();
        }


        #endregion

        public void InitAllDeviceCmd()
        {
            interval = Convert.ToInt32(AppSettingsHelper.Configuration["Interval"]);
            server_ip = AppSettingsHelper.Configuration["ServerIp"];
            server_port = Convert.ToInt32(AppSettingsHelper.Configuration["ServerPort"]);
            NetWorkNum = Convert.ToInt32(AppSettingsHelper.Configuration["NetWorkNum"]);
            string deviceid = AppSettingsHelper.Configuration["DeciceIds"];
            string[] ids = deviceid.Split(',');
            for (int i = 0; i < ids.Length; i++)
            {
                DeviceInfo deviceInfo = new DeviceInfo();
                if (i == 0)
                {
                    deviceInfo.flag = 1;
                }
                deviceInfo.deviceId = Convert.ToInt32(ids[i]);
                byte[] deviceno = BitConverter.GetBytes(deviceInfo.deviceId);
                byte[] crcdata = new byte[8] { 0xA7, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00 };
                crcdata[1] = deviceno[1];
                crcdata[2] = deviceno[0];
                byte[] crcValue = Tools.ComputeCrc16(crcdata);
                byte[] data = new byte[10];
                Array.Copy(crcdata, 0, data, 0, 8);
                data[8] = crcValue[1];
                data[9] = crcValue[0];
                deviceInfo.querycmd = data;
                deviceInfos.Add(deviceInfo);
            }
        }

        public static bool SendToSerial(byte[] cmd)
        {
            try
            {
                myS0SerialPort_1.Write(cmd, 0, cmd.Length);
            }
            catch (Exception e)
            {
                serial_state = false;
            }
            return true;
        }

        public void Check485()
        {
            Task t = Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    try
                    {
                        if (!serial_state)
                        {
                            string portname = AppSettingsHelper.Configuration["PortName"];
                            int baudRate = Convert.ToInt32(AppSettingsHelper.Configuration["BaudRate"]);
                            int parity = Convert.ToInt32(AppSettingsHelper.Configuration["Parity"]);
                            int databits = Convert.ToInt32(AppSettingsHelper.Configuration["DataBits"]);
                            int stopbits = Convert.ToInt32(AppSettingsHelper.Configuration["StopBits"]);
                            OpenSerialPort(portname, baudRate, parity, databits, stopbits);
                        }
                        Task.Delay(30000).Wait();
                    }
                    catch (Exception ex)
                    {
                        Task.Delay(30000).Wait();
                    }
                }
            });
        }
        public void CmdSend()
        {
            Task t = Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    try
                    {
                        foreach (var item in deviceInfos)
                        {
                            if (cmdInfos.Count > 0)
                            {
                                foreach (var cmds in cmdInfos)
                                {
                                    try
                                    {
                                        myS0SerialPort_1.Write(cmds.cmd, 0, cmds.cmd.Length);
                                        cmdInfos.Remove(cmds);
                                    }
                                    catch (Exception e)
                                    {
                                    }
                                    Task.Delay(interval).Wait();
                                }
                            }
                            else
                            {
                                try
                                {
                                    myS0SerialPort_1.Write(item.querycmd, 0, item.querycmd.Length);
                                }
                                catch (Exception e)
                                {
                                }
                                Task.Delay(interval).Wait();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Task.Delay(interval).Wait();
                    }
                }
            });
        }

        public void TcpServerConnect()
        {
            Task task = new Task(async () =>
            {
                while (true)
                {
                    if (!server_flag)
                    {
                        bool result = ConnectServer(server_ip, server_port);
                        if (result)
                        {
                            server_flag = true;
                        }
                    }
                    await Task.Delay(10000);

                }
            });
            task.Start();
        }

        public bool ConnectServer(string serverIP, int port)
        {
            try
            {
                server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                server.Connect(serverIP, port);
                //server.ReceiveTimeout = 10000;
                thread = new Thread(StartReceive);
                thread.Start(server);
                return true;
            }
            catch (Exception e)
            {
                return false;
            }
        }

        public void StartReceive(object obj)
        {
            byte[] buffer = new byte[2048];
            int length = 0;
            while (true)
            {
                try
                {
                    length = server.Receive(buffer);
                    if (length == 0)
                    {
                        break;
                    }
                    else
                    {
                        byte[] data = buffer.Skip(0).Take(length).ToArray();
                        CmdInfo cmdInfo = new CmdInfo();
                        cmdInfo.cmd = data;
                        cmdInfos.Add(cmdInfo);
                    }
                }
                catch (Exception ex)
                {
                    continue;
                }
            }
        }

        public bool SendToServerMsg(byte[] senddata)
        {
            lock (sendlocker)
            {
                try
                {
                    if (server.Connected == true)
                    {
                        try
                        {
                            server.Send(senddata);
                        }
                        catch (Exception ex)
                        {
                            return false;
                        }
                    }
                    else
                    {
                        server_flag = false;
                    }
                    return true;
                }
                catch (Exception ex)
                {
                    server_flag = false;
                    return false;
                }
            }
        }
    }
}
